home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 41 / Amiga Format CD41 (1999-06)(Future Publishing)(GB)[!][issue 1999-07].iso / -seriously_amiga- / programming / other / scrollingtricks / source / scroller_xylimited / main.c < prev    next >
C/C++ Source or Header  |  1999-04-19  |  23KB  |  1,173 lines

  1. #include <exec/exec.h>
  2. #include <dos/dos.h>
  3. #include <intuition/intuition.h>
  4. #include <graphics/gfx.h>
  5. #include <hardware/custom.h>
  6. #include <hardware/dmabits.h>
  7.  
  8. #ifdef __MAXON__
  9. #include <pragma/exec_lib.h>
  10. #include <pragma/dos_lib.h>
  11. #include <pragma/graphics_lib.h>
  12. #include <pragma/intuition_lib.h>
  13. #else
  14. #include <proto/exec.h>
  15. #include <proto/dos.h>
  16. #include <proto/graphics.h>
  17. #include <proto/intuition.h>
  18. #endif
  19.  
  20. #include <stdio.h>
  21. #include <string.h>
  22.  
  23. #include "hardware.h"
  24. #include "cop.h"
  25. #include "map.h"
  26.  
  27.  
  28. #define ARG_TEMPLATE "SPEED/S,NTSC/S,HOW/S,FMODE/N/K"
  29. #define ARG_SPEED 0
  30. #define ARG_NTSC  1
  31. #define ARG_HOW   2
  32. #define ARG_FMODE 3
  33. #define NUM_ARGS  4
  34.  
  35. #define MAPNAME        "maps/scroller.raw"
  36. #define BLOCKSNAME    "blocks/demoblocks.raw"
  37.  
  38. #define SCREENWIDTH  320
  39. #define SCREENHEIGHT 256
  40. #define EXTRAWIDTH  64
  41. #define EXTRAHEIGHT 32
  42. #define SCREENBYTESPERROW (SCREENWIDTH / 8)
  43.  
  44. #define BITMAPWIDTH (SCREENWIDTH + EXTRAWIDTH)
  45. #define BITMAPBYTESPERROW (BITMAPWIDTH / 8)
  46. #define BITMAPHEIGHT (SCREENHEIGHT + EXTRAHEIGHT)
  47.  
  48. #define BLOCKSWIDTH 320
  49. #define BLOCKSHEIGHT 200
  50. #define BLOCKSDEPTH 4
  51. #define BLOCKSCOLORS (1L << BLOCKSDEPTH)
  52. #define BLOCKWIDTH 16
  53. #define BLOCKHEIGHT 16
  54. #define BLOCKSBYTESPERROW (BLOCKSWIDTH / 8)
  55. #define BLOCKSPERROW (BLOCKSWIDTH / BLOCKWIDTH)
  56.  
  57. #define NUMSTEPS_X BLOCKWIDTH
  58. #define NUMSTEPS_Y BLOCKHEIGHT
  59.  
  60. #define BITMAPBLOCKSPERROW (BITMAPWIDTH / BLOCKWIDTH)
  61. #define BITMAPBLOCKSPERCOL (BITMAPHEIGHT / BLOCKHEIGHT)
  62.  
  63. #define VISIBLEBLOCKSX (SCREENWIDTH / BLOCKWIDTH)
  64. #define VISIBLEBLOCKSY (SCREENHEIGHT / BLOCKHEIGHT)
  65.  
  66. #define BITMAPPLANELINES (BITMAPHEIGHT * BLOCKSDEPTH)
  67. #define BLOCKPLANELINES  (BLOCKHEIGHT * BLOCKSDEPTH)
  68.  
  69. #define DIWSTART 0x2981
  70. #define DIWSTOP  0x29C1
  71.  
  72. #define PALSIZE (BLOCKSCOLORS * 2)
  73. #define BLOCKSFILESIZE (BLOCKSWIDTH * BLOCKSHEIGHT * BLOCKSPLANES / 8 + PALSIZE)
  74.  
  75. #define DIRECTION_IGNORE 0
  76. #define DIRECTION_LEFT   1
  77. #define DIRECTION_RIGHT  2
  78.  
  79. // calculate how many times (steps) y-scrolling needs to
  80. // blit two blocks instead of one block to make sure a
  81. // complete row is blitted after 16 pixels of y-scrolling
  82. //
  83. // x * 2 + (16 - x) = BITMAPBLOCKSPERROW
  84. // 2x + 16 - x = BITMAPBLOCKSPERROW
  85. // x = BITMAPBLOCKSPERROW - 16
  86.  
  87. #define TWOBLOCKS (BITMAPBLOCKSPERROW - NUMSTEPS_Y)
  88. #define TWOBLOCKSTEP TWOBLOCKS
  89.  
  90. struct IntuitionBase *IntuitionBase;
  91. struct GfxBase *GfxBase;
  92. struct Screen *scr;
  93. struct RastPort *ScreenRastPort;
  94. struct BitMap *BlocksBitmap,*ScreenBitmap;
  95. struct RawMap *Map;
  96. UBYTE     *frontbuffer,*blocksbuffer;
  97.  
  98. WORD    mapposx,mapposy,videoposx,videoposy,block_videoposy;
  99. WORD    mapblockx,mapblocky,stepx,stepy;
  100. WORD    bitmapheight,bitplanemodulo;
  101.  
  102. WORD    *savewordpointer;
  103. WORD    saveword;
  104. BYTE    previous_xdirection;
  105.  
  106. LONG    mapwidth,mapheight;
  107. UBYTE *mapdata;
  108.  
  109. UWORD    colors[BLOCKSCOLORS];
  110.  
  111. LONG    Args[NUM_ARGS];
  112.  
  113. BOOL    option_ntsc,option_how,option_speed;
  114. WORD    option_fetchmode;
  115.  
  116. BPTR    MyHandle;
  117. char    s[256];
  118.  
  119. #if EXTRAWIDTH == 32
  120.  
  121.     // bitmap width aligned to 32 Pixels
  122.     #define MAX_FETCHMODE 2
  123.     #define MAX_FETCHMODE_S "2"
  124.  
  125. #elif EXTRAWIDTH == 64
  126.  
  127.     // bitmap width aligned to 64 Pixels
  128.     #define MAX_FETCHMODE 3
  129.     #define MAX_FETCHMODE_S "3"
  130.  
  131. #else
  132.  
  133.     // bad extrawidth
  134.     #error "EXTRAWIDTH must be either 32 or 64"
  135.  
  136. #endif
  137.  
  138. struct FetchInfo
  139. {
  140.     WORD    ddfstart;
  141.     WORD    ddfstop;
  142.     WORD    modulooffset;
  143.     WORD    bitmapoffset;
  144.     WORD    scrollpixels;
  145. } fetchinfo [] =
  146. {
  147.     {0x30,0xD0,2,0,16},    /* normal         */
  148.     {0x28,0xC8,4,16,32},    /* BPL32          */
  149.     {0x28,0xC8,4,16,32},    /* BPAGEM         */
  150.     {0x18,0xB8,8,48,64}    /* BPL32 + BPAGEM */
  151. };
  152.  
  153. /********************* MACROS ***********************/
  154.  
  155. #define ROUND2BLOCKWIDTH(x)  ((x) & ~(BLOCKWIDTH - 1))
  156. #define ROUND2BLOCKHEIGHT(x) ((x) & ~(BLOCKHEIGHT - 1))
  157.  
  158. /************* SETUP/CLEANUP ROUTINES ***************/
  159.  
  160. static void Cleanup (char *msg)
  161. {
  162.     WORD rc;
  163.     
  164.     if (msg)
  165.     {
  166.         printf("Error: %s\n",msg);
  167.         rc = RETURN_WARN;
  168.     } else {
  169.         rc = RETURN_OK;
  170.     }
  171.  
  172.     if (scr) CloseScreen(scr);
  173.  
  174.     if (ScreenBitmap)
  175.     {
  176.         WaitBlit();
  177.         FreeBitMap(ScreenBitmap);
  178.     }
  179.  
  180.     if (BlocksBitmap)
  181.     {
  182.         WaitBlit();
  183.         FreeBitMap(BlocksBitmap);
  184.     }
  185.  
  186.     if (Map) FreeVec(Map);
  187.     if (MyHandle) Close(MyHandle);
  188.  
  189.     if (GfxBase) CloseLibrary((struct Library *)GfxBase);
  190.     if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
  191.  
  192.     exit(rc);
  193. }
  194.  
  195. static void OpenLibs(void)
  196. {
  197.     if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",39)))
  198.     {
  199.         Cleanup("Can't open intuition.library V39!");
  200.     }
  201.     
  202.     if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",39)))
  203.     {
  204.         Cleanup("Can't open graphics.library V39!");
  205.     }
  206. }
  207.  
  208. static void GetArguments(void)
  209. {
  210.     struct RDArgs *MyArgs;
  211.  
  212.     if (!(MyArgs = ReadArgs(ARG_TEMPLATE,Args,0)))
  213.     {
  214.         Fault(IoErr(),0,s,255);
  215.         Cleanup(s);
  216.     }
  217.  
  218.     if (Args[ARG_SPEED]) option_speed = TRUE;
  219.     if (Args[ARG_NTSC]) option_ntsc = TRUE;
  220.     if (Args[ARG_HOW])
  221.     {
  222.         option_how = TRUE;
  223.         option_speed = FALSE;
  224.     }
  225.  
  226.     if (Args[ARG_FMODE])
  227.     {
  228.         option_fetchmode = *(LONG *)Args[ARG_FMODE];
  229.     }
  230.  
  231.     FreeArgs(MyArgs);
  232.     
  233.     if (option_fetchmode < 0 || option_fetchmode > MAX_FETCHMODE)
  234.     {
  235.         Cleanup("Invalid fetch mode. Must be 0 .. " MAX_FETCHMODE_S "!");
  236.     }
  237.  
  238. }
  239.  
  240. static void OpenMap(void)
  241. {
  242.     LONG l;
  243.  
  244.     if (!(MyHandle = Open(MAPNAME,MODE_OLDFILE)))
  245.     {
  246.         Fault(IoErr(),0,s,255);
  247.         Cleanup(s);
  248.     }
  249.     
  250.     Seek(MyHandle,0,OFFSET_END);
  251.     l = Seek(MyHandle,0,OFFSET_BEGINNING);
  252.  
  253.     if (!(Map = AllocVec(l,MEMF_PUBLIC)))
  254.     {
  255.         Cleanup("Out of memory!");
  256.     }
  257.     
  258.     if (Read(MyHandle,Map,l) != l)
  259.     {
  260.         Fault(IoErr(),0,s,255);
  261.         Cleanup(s);
  262.     }
  263.     
  264.     Close(MyHandle);MyHandle = 0;
  265.     
  266.     mapdata = Map->data;
  267.     mapwidth = Map->mapwidth;
  268.     mapheight = Map->mapheight;
  269. }
  270.  
  271. static void OpenBlocks(void)
  272. {
  273.     LONG l;
  274.  
  275.     if (!(BlocksBitmap = AllocBitMap(BLOCKSWIDTH,
  276.                                                BLOCKSHEIGHT,
  277.                                                BLOCKSDEPTH,
  278.                                                BMF_STANDARD | BMF_INTERLEAVED,
  279.                                                0)))
  280.     {
  281.         Cleanup("Can't alloc blocks bitmap!");
  282.     }
  283.     
  284.     if (!(MyHandle = Open(BLOCKSNAME,MODE_OLDFILE)))
  285.     {
  286.         Fault(IoErr(),0,s,255);
  287.         Cleanup(s);
  288.     }
  289.     
  290.     if (Read(MyHandle,colors,PALSIZE) != PALSIZE)
  291.     {
  292.         Fault(IoErr(),0,s,255);
  293.         Cleanup(s);
  294.     }
  295.     
  296.     l = BLOCKSWIDTH * BLOCKSHEIGHT * BLOCKSDEPTH / 8;
  297.     
  298.     if (Read(MyHandle,BlocksBitmap->Planes[0],l) != l)
  299.     {
  300.         Fault(IoErr(),0,s,255);
  301.         Cleanup(s);
  302.     }
  303.     
  304.     Close(MyHandle);MyHandle = 0;
  305.     
  306.     blocksbuffer = BlocksBitmap->Planes[0];
  307. }
  308.  
  309. static void OpenDisplay(void)
  310. {    
  311.     struct DimensionInfo diminfo;
  312.     DisplayInfoHandle        dih;
  313.     ULONG                        modeid;
  314.     LONG                        l;
  315.     
  316.     bitmapheight = BITMAPHEIGHT +
  317.                         (mapwidth / BITMAPBLOCKSPERROW / BLOCKSDEPTH) + 1 +
  318.                         3;
  319.  
  320.     if (!(ScreenBitmap = AllocBitMap(BITMAPWIDTH,bitmapheight,BLOCKSDEPTH,BMF_STANDARD | BMF_INTERLEAVED | BMF_CLEAR,0)))
  321.     {
  322.         Cleanup("Can't alloc screen bitmap!");
  323.     }
  324.  
  325.     frontbuffer = ScreenBitmap->Planes[0];
  326.     frontbuffer += (fetchinfo[option_fetchmode].bitmapoffset / 8);
  327.  
  328.     if (!(TypeOfMem(ScreenBitmap->Planes[0]) & MEMF_CHIP))
  329.     {
  330.         Cleanup("Screen bitmap is not in CHIP RAM!?? If you have a gfx card try disabling \"planes to fast\" or similiar options in your RTG system!");
  331.     }
  332.  
  333.     l = GetBitMapAttr(ScreenBitmap,BMA_FLAGS);
  334.     
  335.     if (!(GetBitMapAttr(ScreenBitmap,BMA_FLAGS) & BMF_INTERLEAVED))
  336.     {
  337.         Cleanup("Screen bitmap is not in interleaved format!??");
  338.     }
  339.     
  340.     if (option_how)
  341.     {
  342.         modeid = INVALID_ID;
  343.  
  344.         if ((dih = FindDisplayInfo(VGAPRODUCT_KEY)))
  345.         {
  346.             if (GetDisplayInfoData(dih,(APTR)&diminfo,sizeof(diminfo),DTAG_DIMS,0))
  347.             {
  348.                 if (diminfo.MaxDepth >= BLOCKSDEPTH) modeid = VGAPRODUCT_KEY;
  349.             }
  350.         }
  351.         if (modeid == INVALID_ID)
  352.         {
  353.             if (option_ntsc)
  354.             {
  355.                 modeid = NTSC_MONITOR_ID | HIRESLACE_KEY;
  356.             } else {
  357.                 modeid = PAL_MONITOR_ID | HIRESLACE_KEY;
  358.             }
  359.         }
  360.     } else {
  361.         if (option_ntsc)
  362.         {
  363.             modeid = NTSC_MONITOR_ID;
  364.         } else {
  365.             modeid = PAL_MONITOR_ID;
  366.         }
  367.     }
  368.  
  369.     if (!(scr = OpenScreenTags(0,SA_Width,BITMAPWIDTH,
  370.                                           SA_Height,bitmapheight,
  371.                                           SA_Depth,BLOCKSDEPTH,
  372.                                           SA_DisplayID,modeid,
  373.                                           SA_BitMap,ScreenBitmap,
  374.                                           option_how ? SA_Overscan : TAG_IGNORE,OSCAN_TEXT,
  375.                                           option_how ? SA_AutoScroll : TAG_IGNORE,TRUE,
  376.                                           SA_Quiet,TRUE,
  377.                                           TAG_DONE)))
  378.     {
  379.         Cleanup("Can't open screen!");
  380.     }
  381.  
  382.     if (scr->RastPort.BitMap->Planes[0] != ScreenBitmap->Planes[0])
  383.     {
  384.         Cleanup("Screen was not created with the custom bitmap I supplied!??");
  385.     }
  386.     
  387.     ScreenRastPort = &scr->RastPort;
  388.     
  389.     LoadRGB4(&scr->ViewPort,colors,BLOCKSCOLORS);
  390. }
  391.  
  392. static void InitCopperlist(void)
  393. {
  394.     WORD    *wp;
  395.     ULONG    plane,plane2;
  396.     LONG    l;
  397.  
  398.     WaitVBL();
  399.  
  400.     custom->dmacon = 0x7FFF;
  401.     custom->beamcon0 = option_ntsc ? 0 : DISPLAYPAL;
  402.  
  403.     CopFETCHMODE[1] = option_fetchmode;
  404.     
  405.     // bitplane control registers
  406.  
  407.     CopBPLCON0[1] = ((BLOCKSDEPTH * BPL0_BPU0_F) & BPL0_BPUMASK) +
  408.                          ((BLOCKSDEPTH / 8) * BPL0_BPU3_F) +
  409.                          BPL0_COLOR_F +
  410.                          (option_speed ? 0 : BPL0_USEBPLCON3_F);
  411.  
  412.     CopBPLCON1[1] = 0;
  413.  
  414.     CopBPLCON3[1] = BPLCON3_BRDNBLNK;
  415.  
  416.     // bitplane modulos
  417.  
  418.     l = BITMAPBYTESPERROW * BLOCKSDEPTH -
  419.          SCREENBYTESPERROW - fetchinfo[option_fetchmode].modulooffset;
  420.  
  421.     CopBPLMODA[1] = l;
  422.     CopBPLMODB[1] = l;
  423.     
  424.     CopVIDEOSPLITRESETMODULO[1] = l;
  425.     CopVIDEOSPLITRESETMODULO[3] = l;
  426.  
  427.     bitplanemodulo = l;
  428.  
  429.     // display window start/stop
  430.     
  431.     CopDIWSTART[1] = DIWSTART;
  432.     CopDIWSTOP[1] = DIWSTOP;
  433.     
  434.     // display data fetch start/stop
  435.     
  436.     CopDDFSTART[1] = fetchinfo[option_fetchmode].ddfstart;
  437.     CopDDFSTOP[1]  = fetchinfo[option_fetchmode].ddfstop;
  438.     
  439.     // plane pointers
  440.  
  441.     wp = CopPLANE1H;
  442.  
  443.     for(l = 0;l < BLOCKSDEPTH;l++)
  444.     {
  445.         plane = (ULONG)ScreenBitmap->Planes[l];
  446.         
  447.         wp[1] = plane >> 16;
  448.         wp[3] = plane & 0xFFFF;
  449.  
  450.         wp += 4;
  451.     }
  452.  
  453.     // setup modulo trick
  454.  
  455.     plane = (ULONG)ScreenBitmap->Planes[0];
  456.  
  457.     plane2 = plane +
  458.                 (BITMAPHEIGHT - 1) * BITMAPBYTESPERROW * BLOCKSDEPTH +
  459.                 SCREENBYTESPERROW +
  460.                 fetchinfo[option_fetchmode].modulooffset;
  461.  
  462.     l = (plane - plane2) & 0xFFFF;
  463.  
  464.     CopVIDEOSPLITMODULO[1] = l;
  465.     CopVIDEOSPLITMODULO[3] = l;
  466.     
  467.     CopVIDEOSPLITMODULO[1] = l;
  468.     CopVIDEOSPLITMODULO[3] = l;
  469.  
  470.     /**/
  471.     
  472.     custom->intena = 0x7FFF;
  473.     
  474.     custom->dmacon = DMAF_SETCLR | DMAF_BLITTER | DMAF_COPPER | DMAF_RASTER | DMAF_MASTER;
  475.  
  476.     custom->cop2lc = (ULONG)CopperList;    
  477. };
  478.  
  479. /******************* SCROLLING **********************/
  480.  
  481. static void DrawBlock(LONG x,LONG y,LONG mapx,LONG mapy)
  482. {
  483.     UBYTE block;
  484.  
  485.     // x = in pixels
  486.     // y = in "planelines" (1 realline = BLOCKSDEPTH planelines)
  487.  
  488.     x = (x / 8) & 0xFFFE;
  489.     
  490.     block = mapdata[mapy * mapwidth + mapx];
  491.  
  492.     mapx = (block % BLOCKSPERROW) * (BLOCKWIDTH / 8);
  493.     mapy = (block / BLOCKSPERROW) * (BLOCKPLANELINES * BLOCKSBYTESPERROW);
  494.     
  495.     if (option_how) OwnBlitter();
  496.  
  497.     HardWaitBlit();
  498.         
  499.     custom->bltcon0 = 0x9F0;    // use A and D. Op: D = A
  500.     custom->bltcon1 = 0;
  501.     custom->bltafwm = 0xFFFF;
  502.     custom->bltalwm = 0xFFFF;
  503.     custom->bltamod = BLOCKSBYTESPERROW - (BLOCKWIDTH / 8);
  504.     custom->bltdmod = BITMAPBYTESPERROW - (BLOCKWIDTH / 8);
  505.     custom->bltapt  = blocksbuffer + mapy + mapx;
  506.     custom->bltdpt     = frontbuffer + y * BITMAPBYTESPERROW + x;
  507.     
  508.     custom->bltsize = BLOCKPLANELINES * 64 + (BLOCKWIDTH / 16);
  509.  
  510.     if (option_how) DisownBlitter();
  511. }
  512.  
  513. static void FillScreen(void)
  514. {
  515.     WORD a,b,x,y;
  516.     
  517.     for (b = 0;b < BITMAPBLOCKSPERCOL;b++)
  518.     {
  519.         for (a = 0;a < BITMAPBLOCKSPERROW;a++)
  520.         {
  521.             x = a * BLOCKWIDTH;
  522.             y = b * BLOCKPLANELINES;
  523.  
  524.             DrawBlock(x,y,a,b);
  525.         }
  526.     }
  527. }
  528.  
  529. static void ScrollUp(void)
  530. {
  531.     WORD mapx,mapy,x,y;
  532.  
  533.     if (mapposy < 1) return;
  534.  
  535.     mapposy--;
  536.     mapblocky = mapposy / BLOCKHEIGHT;
  537.     stepy = mapposy & (NUMSTEPS_Y - 1);
  538.     
  539.     videoposy--;
  540.     if (videoposy < 0) videoposy += BITMAPHEIGHT;
  541.     if (stepy == (NUMSTEPS_Y - 1))
  542.     {
  543.         block_videoposy -= BLOCKHEIGHT;
  544.         if (block_videoposy < 0) block_videoposy += BITMAPHEIGHT;
  545.     }
  546.     
  547.     if (stepy == (NUMSTEPS_Y - 1))
  548.     {
  549.         // a complete row is filled up
  550.         // : the next fill up row will be BLOCKHEIGHT (16)
  551.         // pixels at the top, so we have to adjust
  552.         // the fillup column (for x scrolling), but
  553.         // only if the fillup column (x) contains some
  554.         // fill up blocks
  555.         
  556.         if (stepx)
  557.         {
  558.             // step 1: blit the 1st block in the fillup
  559.             //         col (x). There can only be 0 or
  560.             //         [2 or more] fill up blocks in the
  561.             //         actual implementation, so we do
  562.             //         not need to check previous_xdirection
  563.             //         for this blit
  564.             
  565.             mapx = mapblockx + BITMAPBLOCKSPERROW;
  566.             mapy = mapblocky + 1;
  567.             
  568.             x = ROUND2BLOCKWIDTH(videoposx);
  569.             y = (block_videoposy + BLOCKHEIGHT) % BITMAPHEIGHT;
  570.             y *= BLOCKSDEPTH;
  571.  
  572.             DrawBlock(x + BITMAPWIDTH,y,mapx,mapy);
  573.             
  574.             // step 2: remove the (former) bottommost fill up
  575.             // block
  576.             
  577.             if (previous_xdirection == DIRECTION_RIGHT)
  578.             {
  579.                 *savewordpointer = saveword;
  580.             }
  581.             
  582.             mapy = stepx + 2;
  583.  
  584.             // we blit a 'left' block
  585.  
  586.             y = (block_videoposy + (mapy * BLOCKHEIGHT)) % BITMAPHEIGHT;
  587.             y *= BLOCKSDEPTH;
  588.             
  589.             savewordpointer = (WORD *)(frontbuffer + (y * BITMAPBYTESPERROW) + (x / 8));
  590.             saveword = *savewordpointer;
  591.  
  592.             mapx -= BITMAPBLOCKSPERROW;
  593.             mapy += mapblocky;
  594.  
  595.             DrawBlock(x,y,mapx,mapy);
  596.             
  597.             previous_xdirection = DIRECTION_LEFT;
  598.  
  599.         } /* if (stepx) */
  600.         
  601.     } /* if (stepy == NUMSTEPS_Y - 1) */
  602.  
  603.  
  604.     mapx = stepy;
  605.     mapy = mapblocky;
  606.     
  607.     y = block_videoposy * BLOCKSDEPTH;
  608.  
  609.    if (mapx >= TWOBLOCKSTEP)
  610.    {
  611.        // blit only one block
  612.        
  613.        mapx += TWOBLOCKSTEP;
  614.  
  615.        x = mapx * BLOCKWIDTH + ROUND2BLOCKWIDTH(videoposx);
  616.  
  617.        mapx += mapblockx;
  618.  
  619.        DrawBlock(x,y,mapx,mapy);
  620.        
  621.    } else {
  622.        // blit two blocks
  623.        
  624.        mapx *= 2;
  625.  
  626.        x = mapx * BLOCKWIDTH + ROUND2BLOCKWIDTH(videoposx);
  627.  
  628.         mapx += mapblockx;
  629.  
  630.        DrawBlock(x,y,mapx,mapy);
  631.        
  632.        x += BLOCKWIDTH;
  633.  
  634.        DrawBlock(x,y,mapx + 1,mapy);
  635.        
  636.    }
  637. }
  638.  
  639. static void ScrollDown(void)
  640. {
  641.     WORD mapx,mapy,x,y,y2;
  642.  
  643.     if (mapposy >= (mapheight * BLOCKHEIGHT - SCREENHEIGHT - BLOCKHEIGHT)) return;
  644.     
  645.     mapx = stepy;
  646.     mapy = mapblocky + BITMAPBLOCKSPERCOL;
  647.     
  648.     y = block_videoposy * BLOCKSDEPTH;
  649.  
  650.    if (mapx >= TWOBLOCKSTEP)
  651.    {
  652.        // blit only one block
  653.        
  654.        mapx += TWOBLOCKSTEP;
  655.  
  656.        x = mapx * BLOCKWIDTH + ROUND2BLOCKWIDTH(videoposx);
  657.  
  658.        mapx += mapblockx;
  659.  
  660.        DrawBlock(x,y,mapx,mapy);
  661.        
  662.    } else {
  663.        // blit two blocks
  664.        
  665.        mapx *= 2;
  666.  
  667.        x = mapx * BLOCKWIDTH + ROUND2BLOCKWIDTH(videoposx);
  668.  
  669.        mapx += mapblockx;
  670.        
  671.        DrawBlock(x,y,mapx,mapy);
  672.        
  673.        x += BLOCKWIDTH;
  674.  
  675.        DrawBlock(x,y,mapx + 1,mapy);
  676.    }
  677.  
  678.     mapposy++;
  679.     mapblocky = mapposy / BLOCKHEIGHT;
  680.     stepy = mapposy & (NUMSTEPS_Y - 1);
  681.     
  682.     videoposy++;
  683.     if (videoposy >= BITMAPHEIGHT) videoposy -= BITMAPHEIGHT;
  684.     
  685.     if (!stepy)
  686.     {
  687.         block_videoposy += BLOCKHEIGHT;
  688.         if (block_videoposy >= BITMAPHEIGHT) block_videoposy -= BITMAPHEIGHT;
  689.     }
  690.  
  691.     if (stepy == 0)
  692.     {
  693.         // a complete row is filled up
  694.         // : the next fill up row will be BLOCKHEIGHT (16)
  695.         // pixels at the bottom, so we have to adjust
  696.         // the fillup column (for x scrolling), but
  697.         // only if the fillup column (x) contains some
  698.         // fill up blocks
  699.         
  700.         if (stepx)
  701.         {
  702.             // step 1: blit the 1st block in the fillup
  703.             //         row (y) because this block must
  704.             //         not be part of the fillup col (x)
  705.             //         instead it is for exclusive use
  706.             //         by the fillup row
  707.             
  708.             mapx = mapblockx;
  709.             mapy = mapblocky;
  710.             
  711.             x = ROUND2BLOCKWIDTH(videoposx);
  712.             y = block_videoposy * BLOCKSDEPTH;
  713.             
  714.             DrawBlock(x,y,mapx,mapy);
  715.             
  716.             // step 2: blit the (new) bottommost fill up
  717.             // block
  718.             
  719.             if (previous_xdirection == DIRECTION_LEFT)
  720.             {
  721.                 *savewordpointer = saveword;
  722.             }
  723.             
  724.             mapy = stepx + 1;
  725.  
  726.             // we blit a 'right-block'
  727.  
  728.             x += BITMAPWIDTH;
  729.  
  730.             y = (block_videoposy + (mapy * BLOCKHEIGHT)) % BITMAPHEIGHT;
  731.             y *= BLOCKSDEPTH;
  732.  
  733.             y2 = (y + BLOCKPLANELINES - 1) % BITMAPPLANELINES;
  734.             
  735.             savewordpointer = (WORD *)(frontbuffer + (y2 * BITMAPBYTESPERROW) + (x / 8));
  736.             saveword = *savewordpointer;
  737.  
  738.             mapx += BITMAPBLOCKSPERROW;
  739.             mapy += mapblocky;
  740.  
  741.             DrawBlock(x,y,mapx,mapy);
  742.             
  743.             previous_xdirection = DIRECTION_RIGHT;
  744.         } /* if (stepx) */
  745.         
  746.     } /* if (stepy == 0) */
  747.     
  748.  
  749. }
  750.  
  751. static void ScrollLeft(void)
  752. {
  753.     WORD mapx,mapy,x,y;
  754.     
  755.     if (mapposx < 1) return;
  756.     
  757.     mapposx--;
  758.     mapblockx = mapposx / BLOCKWIDTH;
  759.     stepx = mapposx & (NUMSTEPS_X - 1);
  760.  
  761.     videoposx--;
  762.  
  763.     if (stepx == (NUMSTEPS_X - 1))
  764.     {
  765.         // a complete column is filled up
  766.         // : the next fill up column will be BLOCKWIDTH (16)
  767.         // pixels at the left, so we have to adjust
  768.         // the fillup row (for y scrolling)
  769.         
  770.         // step 1: blit the block which came in at
  771.         //         the left side and which might or
  772.         //         might not be a fill up block
  773.         
  774.         mapx = mapblockx;
  775.         mapy = mapblocky;
  776.  
  777.         if (stepy)
  778.         {
  779.             // there is a fill up block
  780.             // so block which comes in left is
  781.             // a fillup block
  782.             
  783.             mapy += BITMAPBLOCKSPERCOL;
  784.         }
  785.  
  786.         x = ROUND2BLOCKWIDTH(videoposx);
  787.         y = block_videoposy * BLOCKSDEPTH;
  788.         
  789.         DrawBlock(x,y,mapx,mapy);
  790.         
  791.         // step 2: remove the (former) rightmost fillup-block
  792.         
  793.         mapx = stepy;
  794.         if (mapx)
  795.         {
  796.             // there is a fill up block;
  797.             
  798.             if (mapx >= TWOBLOCKSTEP)
  799.             {
  800.                 mapx += TWOBLOCKSTEP;
  801.             } else {
  802.                 mapx *= 2;
  803.             }
  804.                         
  805.             x = ROUND2BLOCKWIDTH(videoposx) + (mapx * BLOCKWIDTH);
  806.             y = block_videoposy * BLOCKSDEPTH;
  807.             
  808.             mapx += mapblockx;
  809.             mapy -= BITMAPBLOCKSPERCOL;
  810.             DrawBlock(x,y,mapx,mapy);
  811.         }
  812.  
  813.     }
  814.  
  815.  
  816.     mapx = mapblockx;
  817.     mapy = stepx + 1;
  818.  
  819.     x = ROUND2BLOCKWIDTH(videoposx);
  820.     
  821.     if (previous_xdirection == DIRECTION_RIGHT)
  822.     {
  823.         HardWaitBlit();
  824.         *savewordpointer = saveword;
  825.     }
  826.  
  827.     if (mapy == 1)
  828.     {
  829.         // blit two blocks
  830.  
  831.         mapy += mapblocky;
  832.         
  833.         y = (block_videoposy + (1 * BLOCKHEIGHT)) % BITMAPHEIGHT;
  834.         y *= BLOCKSDEPTH;
  835.  
  836.         savewordpointer = (WORD *)(frontbuffer + (y * BITMAPBYTESPERROW) + (x / 8));
  837.         saveword = *savewordpointer;
  838.         
  839.         DrawBlock(x,y,mapx,mapy);
  840.         
  841.         y = (y + BLOCKPLANELINES) % BITMAPPLANELINES;
  842.  
  843.         DrawBlock(x,y,mapx,mapy + 1);
  844.  
  845.     } else {
  846.         // blit one block
  847.  
  848.         mapy ++;
  849.         
  850.         y = (block_videoposy + (mapy * BLOCKHEIGHT)) % BITMAPHEIGHT;
  851.         y *= BLOCKSDEPTH;
  852.  
  853.         mapy += mapblocky;
  854.  
  855.         savewordpointer = (WORD *)(frontbuffer + (y * BITMAPBYTESPERROW) + (x / 8));
  856.         saveword = *savewordpointer;
  857.  
  858.         DrawBlock(x,y,mapx,mapy);
  859.     }
  860.     
  861.     if (stepx)
  862.     {
  863.         previous_xdirection = DIRECTION_LEFT;
  864.     } else {
  865.         previous_xdirection = DIRECTION_IGNORE;
  866.     }
  867. }
  868.  
  869. static void ScrollRight(void)
  870. {
  871.     WORD mapx,mapy,x,y,y2;
  872.     
  873.     if (mapposx >= (mapwidth * BLOCKWIDTH - SCREENWIDTH - BLOCKWIDTH)) return;
  874.  
  875.     mapx = mapblockx + BITMAPBLOCKSPERROW;
  876.     mapy = stepx + 1;
  877.  
  878.     x = ROUND2BLOCKWIDTH(videoposx);
  879.     
  880.     if (previous_xdirection == DIRECTION_LEFT)
  881.     {
  882.         HardWaitBlit();
  883.         *savewordpointer = saveword;
  884.     }
  885.  
  886.     if (mapy == 1)
  887.     {
  888.         // blit two blocks
  889.  
  890.         mapy += mapblocky;
  891.         
  892.         y = (block_videoposy + (1 * BLOCKHEIGHT)) % BITMAPHEIGHT;
  893.         y *= BLOCKSDEPTH;
  894.  
  895.         DrawBlock(x + BITMAPWIDTH,y,mapx,mapy);
  896.         
  897.         y = (y + BLOCKPLANELINES) % BITMAPPLANELINES;
  898.         y2 = (y + BLOCKPLANELINES - 1) % BITMAPPLANELINES;
  899.         
  900.         savewordpointer = (WORD *)(frontbuffer + (y2 * BITMAPBYTESPERROW) + ((x + BITMAPWIDTH) / 8));
  901.         saveword = *savewordpointer;
  902.  
  903.         DrawBlock(x + BITMAPWIDTH,y,mapx,mapy + 1);
  904.  
  905.     } else {
  906.         // blit one block
  907.  
  908.         mapy ++;
  909.         
  910.         y = (block_videoposy + (mapy * BLOCKHEIGHT)) % BITMAPHEIGHT;
  911.         y *= BLOCKSDEPTH;
  912.         y2 = (y + BLOCKPLANELINES - 1) % BITMAPPLANELINES;
  913.         
  914.         mapy += mapblocky;
  915.  
  916.         savewordpointer = (WORD *)(frontbuffer + (y2 * BITMAPBYTESPERROW) + ((x + BITMAPWIDTH) / 8));
  917.         saveword = *savewordpointer;
  918.  
  919.         DrawBlock(x + BITMAPWIDTH,y,mapx,mapy);
  920.     }
  921.     
  922.     //
  923.     
  924.     mapposx++;
  925.     mapblockx = mapposx / BLOCKWIDTH;
  926.     stepx = mapposx & (NUMSTEPS_X - 1);
  927.  
  928.     videoposx++;
  929.     
  930.     if (stepx == 0)
  931.     {
  932.         // a complete column is filled up
  933.         // : the next fill up column will be BLOCKWIDTH (16)
  934.         // pixels at the right, so we have to adjust
  935.         // the fillup row (for y scrolling)
  936.         
  937.         // step 1: blit the block which came in at
  938.         //         the right side and which is never
  939.         //         a fill up block
  940.         
  941.         mapx = mapblockx + BITMAPBLOCKSPERROW - 1;
  942.         mapy = mapblocky;
  943.         
  944.         x = ROUND2BLOCKWIDTH(videoposx) + (BITMAPBLOCKSPERROW - 1) * BLOCKWIDTH;
  945.         y = block_videoposy * BLOCKSDEPTH;
  946.         
  947.         DrawBlock(x,y,mapx,mapy);
  948.         
  949.         // step 2: blit the (new) rightmost fillup-block
  950.         
  951.         mapx = stepy;
  952.         if (mapx)
  953.         {
  954.             // there is a fill up block;
  955.             
  956.             if (mapx >= TWOBLOCKSTEP)
  957.             {
  958.                 mapx += (TWOBLOCKSTEP - 1);
  959.             } else {
  960.                 mapx = mapx * 2 - 1;
  961.             }
  962.                         
  963.             x = ROUND2BLOCKWIDTH(videoposx) + (mapx * BLOCKWIDTH);
  964.             y = block_videoposy * BLOCKSDEPTH;
  965.  
  966.             mapx += mapblockx;
  967.  
  968.             DrawBlock(x,y,mapx,mapy + BITMAPBLOCKSPERCOL);
  969.         }
  970.     }
  971.  
  972.     if (stepx)
  973.     {
  974.         previous_xdirection = DIRECTION_RIGHT;
  975.     } else {
  976.         previous_xdirection = DIRECTION_IGNORE;
  977.     }
  978. }
  979.  
  980. static void CheckJoyScroll(void)
  981. {
  982.     WORD i,count;
  983.     
  984.     if (JoyFire()) count = 4; else count = 1;
  985.  
  986.     if (JoyUp())
  987.     {
  988.         for(i = 0;i < count;i++)
  989.         {
  990.             ScrollUp();
  991.         }
  992.     }
  993.     
  994.     if (JoyDown())
  995.     {
  996.         for(i = 0;i < count;i++)
  997.         {
  998.             ScrollDown();
  999.         }
  1000.     }
  1001.  
  1002.     if (JoyLeft())
  1003.     {
  1004.         for(i = 0;i < count;i++)
  1005.         {
  1006.             ScrollLeft();
  1007.         }
  1008.     }
  1009.     
  1010.     if (JoyRight())
  1011.     {
  1012.         for(i = 0;i < count;i++)
  1013.         {
  1014.             ScrollRight();
  1015.         }
  1016.     }
  1017.  
  1018. }
  1019.  
  1020. static void UpdateCopperlist(void)
  1021. {
  1022.     ULONG pl;
  1023.     LONG    planeadd,planeaddx;
  1024.     WORD    i,xpos,scroll,yoffset;
  1025.     WORD    *wp;
  1026.  
  1027.     i = fetchinfo[option_fetchmode].scrollpixels;
  1028.  
  1029.     xpos = videoposx + i - 1;
  1030.  
  1031.     planeaddx = (xpos / i) * (i / 8);
  1032.     i = (i - 1) - (xpos & (i - 1));
  1033.     
  1034.     scroll = (i & 15) * 0x11;
  1035.     if (i & 16) scroll |= (0x400 + 0x4000);
  1036.     if (i & 32) scroll |= (0x800 + 0x8000);
  1037.     
  1038.     // set scroll register in BPLCON1
  1039.     
  1040.     CopBPLCON1[1] = scroll;
  1041.  
  1042.     // set top plane pointers
  1043.  
  1044.     yoffset = (videoposy + BLOCKHEIGHT) % BITMAPHEIGHT;
  1045.     planeadd = ((LONG)yoffset) * BLOCKSDEPTH * BITMAPBYTESPERROW;
  1046.     
  1047.     wp = CopPLANE1H;
  1048.  
  1049.     for(i = 0;i < BLOCKSDEPTH;i++)
  1050.     {
  1051.         pl = ((ULONG)ScreenBitmap->Planes[i]) + planeadd + planeaddx;
  1052.         
  1053.         wp[1] = (WORD)(pl >> 16);
  1054.         wp[3] = (WORD)(pl & 0xFFFF);
  1055.         
  1056.         wp += 4;
  1057.     }
  1058.  
  1059.     // set video split wait
  1060.  
  1061.     yoffset = BITMAPHEIGHT - yoffset;
  1062.     yoffset += (DIWSTART >> 8);
  1063.  
  1064.     /* CopVIDEOSPLIT must wait for line (yoffset -1 )
  1065.        CopVIDEOSPLIT2 must wait for line (yoffset)    */
  1066.  
  1067.     if (yoffset <= 255)
  1068.     {
  1069.         CopVIDEOSPLIT[0] = 0x0001;
  1070.         CopVIDEOSPLIT[2] = (yoffset - 1) * 256 + 0x1;
  1071.  
  1072.         CopVIDEOSPLIT2[0] = 0x0001;
  1073.         CopVIDEOSPLIT2[2] = yoffset * 256 + 0x1;
  1074.     } else if (yoffset == 256)
  1075.     {
  1076.         CopVIDEOSPLIT[0] = 0x0001;
  1077.         CopVIDEOSPLIT[2] = 255 * 256 + 0x1;
  1078.         
  1079.         CopVIDEOSPLIT2[0] = 0xFFDF;
  1080.         CopVIDEOSPLIT2[2] = (256 - 256) * 256 + 0x1;
  1081.     } else {
  1082.         CopVIDEOSPLIT[0] = 0xFFDF;
  1083.         CopVIDEOSPLIT[2] = (yoffset - 256 - 1) * 256 + 0x1;
  1084.         
  1085.         CopVIDEOSPLIT2[0] = 0x001;
  1086.         CopVIDEOSPLIT2[2] = (yoffset - 256) * 256 + 0x1;
  1087.     }
  1088.  
  1089.     /* Set video split plane pointers (to top of bitmap):
  1090.  
  1091.          We only set the hiwords. The lowords are automatically
  1092.          correct thanks to the modulo-trick in the copperlist
  1093.          which is setup in UpdateCopperlist().
  1094.     */
  1095.  
  1096.     pl = (ULONG)ScreenBitmap->Planes[0] +
  1097.           planeaddx;
  1098.  
  1099.     // set high words
  1100.  
  1101.     wp = CopPLANE2_1H;
  1102.     
  1103.     for(i = 0;i < BLOCKSDEPTH;i++)
  1104.     {
  1105.         wp[1] = (WORD)(pl >> 16);
  1106.  
  1107.         pl += BITMAPBYTESPERROW * BLOCKSDEPTH;
  1108.         wp += 2;
  1109.     }
  1110.  
  1111. }
  1112.  
  1113. static void MainLoop(void)
  1114. {
  1115.     if (!option_how)
  1116.     {
  1117.         // activate copperlist
  1118.         
  1119.         HardWaitBlit();
  1120.         WaitVBL();
  1121.  
  1122.         custom->copjmp2 = 0;
  1123.     }
  1124.     
  1125.     while (!LMBDown())
  1126.     {
  1127.         if (!option_how)
  1128.         {
  1129.             WaitVBeam(1);
  1130.             UpdateCopperlist();
  1131.             WaitVBeam(200);
  1132.         } else {
  1133.             Delay(1);
  1134.         }
  1135.  
  1136.         if (option_speed) *(WORD *)0xdff180 = 0xFF0;
  1137.         
  1138.         CheckJoyScroll();
  1139.  
  1140.         if (option_speed) *(WORD *)0xdff180 = 0xF00;
  1141.     }
  1142. }
  1143.  
  1144. /********************* MAIN *************************/
  1145.  
  1146. void main(void)
  1147. {
  1148.     OpenLibs();
  1149.     GetArguments();
  1150.     OpenMap();
  1151.     OpenBlocks();
  1152.     OpenDisplay();
  1153.  
  1154.     if (!option_how)
  1155.     {
  1156.         Delay(2*50);
  1157.         KillSystem();
  1158.         InitCopperlist();
  1159.     }
  1160.     FillScreen();
  1161.     
  1162.     MainLoop();
  1163.     
  1164.     if (!option_how)
  1165.     {
  1166.         ActivateSystem();
  1167.     }
  1168.  
  1169.     Cleanup(0);
  1170.     
  1171. }
  1172.  
  1173.